﻿using Grand.Business.Core.Interfaces.Catalog.Tax;
using Grand.Business.Core.Utilities.Catalog;
using Grand.Domain.Tax;
using System.Text.RegularExpressions;

namespace Grand.Business.Catalog.Services.Tax;

public class VatService : IVatService
{
    private readonly TaxSettings _taxSettings;

    public VatService(TaxSettings taxSettings)
    {
        _taxSettings = taxSettings;
    }

    /// <summary>
    ///     Gets VAT Number status
    /// </summary>
    /// <param name="fullVatNumber">Two letter ISO code of a country and VAT number (e.g. GB 111 1111 111)</param>
    /// <returns>VAT Number status</returns>
    public virtual async Task<(VatNumberStatus status, string name, string address, Exception exception)>
        GetVatNumberStatus(string fullVatNumber)
    {
        var name = string.Empty;
        var address = string.Empty;

        if (string.IsNullOrWhiteSpace(fullVatNumber))
            return (VatNumberStatus.Empty, name, address, null);

        fullVatNumber = fullVatNumber.Trim();

        //PL 111 1111 111 or PL 1111111111
        //more advanced regex - http://codeigniter.com/wiki/European_Vat_Checker
        var r = new Regex(@"^(\w{2})(.*)");
        var match = r.Match(fullVatNumber);
        if (!match.Success)
            return (VatNumberStatus.Invalid, name, address, null);
        var twoLetterIsoCode = match.Groups[1].Value;
        var vatNumber = match.Groups[2].Value;

        return await GetVatNumberStatus(twoLetterIsoCode, vatNumber);
    }


    /// <summary>
    ///     Gets VAT Number status
    /// </summary>
    /// <param name="twoLetterIsoCode">Two letter ISO code of a country</param>
    /// <param name="vatNumber">VAT number</param>
    /// <returns>VAT Number status</returns>
    public virtual async Task<(VatNumberStatus status, string name, string address, Exception exception)>
        GetVatNumberStatus(string twoLetterIsoCode, string vatNumber)
    {
        var name = string.Empty;
        var address = string.Empty;

        if (string.IsNullOrEmpty(twoLetterIsoCode))
            return (VatNumberStatus.Empty, name, address, null);

        if (string.IsNullOrEmpty(vatNumber))
            return (VatNumberStatus.Empty, name, address, null);

        if (_taxSettings.EuVatAssumeValid)
            return (VatNumberStatus.Valid, name, address, null);

        if (!_taxSettings.EuVatUseWebService)
            return (VatNumberStatus.Unknown, name, address, null);

        return await DoVatCheck(twoLetterIsoCode, vatNumber);
    }

    /// <summary>
    ///     Performs a basic check of a VAT number for validity
    /// </summary>
    /// <param name="twoLetterIsoCode">Two letter ISO code of a country</param>
    /// <param name="vatNumber">VAT number</param>
    /// <returns>VAT number status</returns>
    public virtual async Task<(VatNumberStatus status, string name, string address, Exception exception)>
        DoVatCheck(string twoLetterIsoCode, string vatNumber)
    {
        vatNumber ??= string.Empty;
        vatNumber = vatNumber.Trim().Replace(" ", "");

        twoLetterIsoCode ??= string.Empty;
        if (!string.IsNullOrEmpty(twoLetterIsoCode))
            //The service returns INVALID_INPUT for country codes that are not uppercase.
            twoLetterIsoCode = twoLetterIsoCode.ToUpper();

        try
        {
            var result = await CheckVatRequest(new VatRequest {
                CountryCode = twoLetterIsoCode,
                VatNumber = vatNumber
            });
            var valid = result.Valid;
            var name = result.Name;
            var address = result.Address;

            return (valid ? VatNumberStatus.Valid : VatNumberStatus.Invalid, name, address, null);
        }
        catch (Exception ex)
        {
            return (VatNumberStatus.Unknown, string.Empty, string.Empty, ex);
        }
    }

    public Task<VatResponse> CheckVatRequest(VatRequest checkVatRequest)
    {
        return Task.FromResult(new VatResponse());
    }
}